package org.simtube.util;

public class DocVector {
	
	private int dim;
	private final double[] v;

	/**
	 * Return the dimension of the vector
	 * @return
	 */
	public int getDim() {
		return dim;
	}
	
	/**
	 * Constructor, you need to use a vector to initialize the object
	 * @param v
	 */
	public DocVector(double[] v) {
		this.v = v;
		this.dim = v.length;
	}
	
	/**
	 * Conduct a vector add operation. The given vector is added to this vector, 
	 * a new result vector is returned, and the original vector will not be changed.
	 * @param va The given adder vector
	 * @return The result vector.
	 */
	public DocVector add(DocVector va) {
		double[] nv = new double[dim];
		double[] vv = va.getVector();
		
		if(va.getDim() != dim)
			System.out.println("Dimension error when adding");
		
		for(int i = 0; i < nv.length; i++) nv[i] = v[i] + vv[i];
		
		return new DocVector(nv);
	}
	
	/**
	 * Conduct a vector minus operation. The given vector is draw away from this vector,
	 * a new result vector is returned, and the original vector will not be affected.
	 * @param va The given vector to decrease
	 * @return The result vector.
	 */
	public DocVector minus(DocVector va) {
		double[] nv = new double[dim];
		double[] vv = va.getVector();
		
		if(va.getDim() != dim)
			System.out.println("Dimension error when minusing vector!");
		
		for(int i = 0; i < dim; i++) nv[i] = v[i] - vv[i];
		
		return new DocVector(nv);
	}
	
	/**
	 * Calculate the inner product of this vector and the given vector va
	 * @param va The given vector
	 * @return The inner product of this vector and va
	 */
	
	public double multiply(DocVector va) {
		double product = 0;
		double[] vv = va.getVector();
		
		if(va.getDim() != dim)
			System.out.println("Dimension error when multiplying vector!");
		
		for(int i = 0; i < dim; i++) product += vv[i] * v[i]; 
		
		return product;
	}
	
	/**
	 * Time all dimension of this vector by a factor
	 * @param factor A factor to multiply
	 * @return The result vector. Notice that the original vector will not be
	 * 		affected.
	 */
	public DocVector multiply(double factor) {
		double[] nv = new double[dim];
		
		for(int i = 0; i < dim; i++) nv[i] = v[i] * factor;
		
		return new DocVector(nv);
	}
	
	/**
	 * Return the array format of the vector
	 * @return An array containing all the elements in this vector
	 */
	public double[] getVector() {
		return v;
	}
	
	/**
	 * Return the norm of this vector (L-2 norm)
	 * @return The norm of this vector
	 */
	public double norm() {
		double nm = 0;
		
		for(int i = 0; i < dim; i++) nm += v[i] * v[i];
		
		return Math.sqrt(nm);
	}
	
	/**
	 * Make a copy of this vector.
	 */
	public DocVector clone() {
		double[] nv = new double[dim];
		
		for(int i = 0; i < dim; i++) nv[i] = v[i];
		
		return new DocVector(nv);
	}
	
	/**
	 * Get a string representation of this vector
	 */
	public String toString() {
		String str = "[";
		
		for(int i = 0; i < dim; i++) {
			if(i == 0)
				str += v[i];
			else
				str += ", " + v[i];
		}
		
		str += "]";
		
		return str;
	}
	
	/**
	 * Normalize the vector and return the normalized vector, the original vector will
	 * not be affected
	 * @return A new normalized vector
	 */
	public DocVector normalize() {
		return this.multiply(1 / this.norm());
	}
	
	/**
	 * Get the sum of all dimensions
	 * 
	 * @return The sum
	 */
	public double dimSum() {
		
		double sum = 0;
		
		for(int i = 0; i < dim; i++) sum += v[i];
		
		return sum;
	}
}
